{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 这个输出解析器包装了另一个输出解析器，如果第一个解析器失败，它会调用另一个LLM来修复任何错误。\n",
    "\n",
    "> 但是除了抛出错误，我们还可以做其他事情。具体来说，我们可以将格式错误的输出以及格式化的指令传递给模型并要求它修复它。\n",
    "\n",
    "> 以下示例，我们将使用PydanticOutputParser输出解析器。如果我们传递给它一个不符合模式的结果，会发生以下情况："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "\n",
    "from langchain_core.output_parsers import PydanticOutputParser\n",
    "from langchain_core.pydantic_v1 import BaseModel, Field\n",
    "from langchain_openai import ChatOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Actor(BaseModel):\n",
    "    name: str = Field(description=\"name of an actor\")\n",
    "    film_names: List[str] = Field(description=\"list of names of films they starred in\")\n",
    "\n",
    "\n",
    "actor_query = \"Generate the filmography for a random actor.\"\n",
    "\n",
    "parser = PydanticOutputParser(pydantic_object=Actor)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "misformatted = \"{'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}\"\n",
    "\n",
    "# misformatted = Actor(name='Tom Hanks', film_names=['Forrest Gump'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValidationError",
     "evalue": "1 validation error for Generation\ntext\n  str type expected (type=type_error.str)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValidationError\u001b[0m                           Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[19], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mparser\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmisformatted\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32md:\\web\\langchain\\langchain-study\\.venv\\Lib\\site-packages\\langchain_core\\output_parsers\\pydantic.py:84\u001b[0m, in \u001b[0;36mPydanticOutputParser.parse\u001b[1;34m(self, text)\u001b[0m\n\u001b[0;32m     75\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mparse\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m TBaseModel:\n\u001b[0;32m     76\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Parse the output of an LLM call to a pydantic object.\u001b[39;00m\n\u001b[0;32m     77\u001b[0m \n\u001b[0;32m     78\u001b[0m \u001b[38;5;124;03m    Args:\u001b[39;00m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     82\u001b[0m \u001b[38;5;124;03m        The parsed pydantic object.\u001b[39;00m\n\u001b[0;32m     83\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[1;32m---> 84\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtext\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32md:\\web\\langchain\\langchain-study\\.venv\\Lib\\site-packages\\langchain_core\\output_parsers\\json.py:98\u001b[0m, in \u001b[0;36mJsonOutputParser.parse\u001b[1;34m(self, text)\u001b[0m\n\u001b[0;32m     89\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mparse\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Any:\n\u001b[0;32m     90\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Parse the output of an LLM call to a JSON object.\u001b[39;00m\n\u001b[0;32m     91\u001b[0m \n\u001b[0;32m     92\u001b[0m \u001b[38;5;124;03m    Args:\u001b[39;00m\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     96\u001b[0m \u001b[38;5;124;03m        The parsed JSON object.\u001b[39;00m\n\u001b[0;32m     97\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[1;32m---> 98\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparse_result([\u001b[43mGeneration\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtext\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtext\u001b[49m\u001b[43m)\u001b[49m])\n",
      "File \u001b[1;32md:\\web\\langchain\\langchain-study\\.venv\\Lib\\site-packages\\pydantic\\v1\\main.py:341\u001b[0m, in \u001b[0;36mBaseModel.__init__\u001b[1;34m(__pydantic_self__, **data)\u001b[0m\n\u001b[0;32m    339\u001b[0m values, fields_set, validation_error \u001b[38;5;241m=\u001b[39m validate_model(__pydantic_self__\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__class__\u001b[39m, data)\n\u001b[0;32m    340\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m validation_error:\n\u001b[1;32m--> 341\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m validation_error\n\u001b[0;32m    342\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m    343\u001b[0m     object_setattr(__pydantic_self__, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m__dict__\u001b[39m\u001b[38;5;124m'\u001b[39m, values)\n",
      "\u001b[1;31mValidationError\u001b[0m: 1 validation error for Generation\ntext\n  str type expected (type=type_error.str)"
     ]
    }
   ],
   "source": [
    "parser.parse(misformatted)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 现在我们可以构造和使用OutputFixingParser。此输出解析器将另一个输出解析器和一个LLM作为参数，用于尝试纠正任何格式错误。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.output_parsers import OutputFixingParser\n",
    "\n",
    "new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'PydanticOutputParser' object is not callable",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[22], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mnew_parser\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparser\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmisformatted\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[1;31mTypeError\u001b[0m: 'PydanticOutputParser' object is not callable"
     ]
    }
   ],
   "source": [
    "new_parser.parser(misformatted)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
